#!/bin/bash
# Desc   : Application service control
# Author : liang.zhou01
# Author : hongzheng.liu
# Modify : 2017.03.25 by liang.zhou01
# Modify : 2017.04.12 by hongzheng.liu

if [[ "$#" < 2 || "$#" > 3 ]]; then
  echo "This scripts argument invalid !"
  echo "Usage: $0 {start|stop|restart|status|stack|heap} app_name [app_port]"  
  exit 1
fi

## 应用设置
APP_USER=finance
APP_NAME=$2
APP_PORT=$3

##当前用户
CURRENT_USER=`whoami| cut -d' ' -f1 | sort | uniq`

echo "current user is $CURRENT_USER"

## 设置应用域名
APP_DOMAIN="$APP_NAME".zkjin.losit # 需要根据环境修改
#APP_DOMAIN="$APP_NAME".msxf.lo

## 应用目录
APP_HOME=/home/finance/App/"$APP_DOMAIN"
[ -d $APP_HOME ] && app_exists=$?
if [[ "$app_exists" != 0 ]]; then
  echo "$APP_HOME not exists."
  exit 1
fi

## 日志目录
APP_LOGS=/home/finance/Logs/"$APP_DOMAIN"

## 服务目录
APP_SERVERS="$APP_HOME"/servers

## 需要指定端口指令判断
if [[ "$1" != "status" ]]; then
  ## 端口参数
  if [[ $APP_PORT == "" ]]; then
    for server_port in `ls -a $APP_SERVERS`
    do
      if [ x"$server_port" != x"." -a x"$server_port" != x".." ]; then
        if [ -d "$APP_SERVERS"/"$server_port" ]; then
          if [[ $APP_PORT == "" ]]; then
            APP_PORT=$server_port
          else
            echo "This scripts argument invalid !"
            echo "Usage: $0 {start|stop|restart} app_name app_port"
            exit 1
          fi
        fi
      fi
    done
  fi
  
  ## 需要指定端口指令，判断是否有端口 
  [ -d $APP_SERVERS/$APP_PORT ] && port_exists=$?
  if [[ "$port_exists" != 0 ]]; then
    echo "$APP_SERVERS/$APP_PORT not exists."
    exit 1
  fi

  ## 内嵌tomcat工作目录
  TMP_PATH=$APP_SERVERS/$APP_PORT

  ## 设置应用停止URI
  APP_SHUTDOWN_URI=localhost:"$APP_PORT"/shutdown

  ## 端口实例进程ID
  APP_PID="$APP_SERVERS"/"$APP_PORT"/pid
fi

## 程序JAR
APP_JAR="$APP_HOME"/release/"$APP_NAME".jar
[ -f $APP_JAR ] && jar_exists=$?

## 当前时间
TIME_NOW=`date +%Y%m%d%H%M%S`

checkStart() {
  if [[ "$jar_exists" != 0 ]]; then
    echo "Application: $APP_JAR not exists."
    exit 1
  fi
  
  if [ -f "$APP_PID" ]; then
    if [ -s "$APP_PID" ]; then
      echo "Existing PID:$APP_PID file found during start."
      if [ -r "$APP_PID" ]; then
        PID=`cat "$APP_PID"`
        ps -p $PID >/dev/null 2>&1
        if [ $? -eq 0 ] ; then
          echo "Application $APP_NAME:$APP_PORT to still be running with PID $PID. Start aborted."
          exit 1
        else
          echo "Removing/clearing stale PID:$APP_PID file."
          rm -f "$APP_PID" >/dev/null 2>&1
          if [ $? != 0 ]; then
            if [ -w "$APP_PID" ]; then
              cat /dev/null > "$APP_PID"
            else
              echo "Unable to remove or clear stale PID:$APP_PID file. Start aborted."
              exit 1
            fi
          fi
        fi
      else
        echo "Unable to read PID:$APP_PID file. Start aborted."
        exit 1
      fi
    else
      rm -f "$APP_PID" >/dev/null 2>&1
      if [ $? != 0 ]; then
        if [ ! -w "$APP_PID" ]; then
          echo "Unable to remove or write to empty PID:$APP_PID file. Start aborted."
          exit 1
        fi
      fi
    fi
  fi
}

checkPid() {
if [ -f "$APP_PID" ]; then
    if [ -s "$APP_PID" ]; then
        kill -0 `cat "$APP_PID"` >/dev/null 2>&1
        if [ $? -gt 0 ]; then
        PID=`ps -ef|grep $APP_NAME| grep $APP_PORT |grep "opt"| awk '{printf \$2}'`
            kill -0  $PID >/dev/null 2>&1
            if [ $? -gt 0 ]; then
                echo "PID:$APP_PID file found but no matching process was found."
                exit 0
            else
                echo "$PID" > "$APP_PID"
            fi
        fi
    else
      echo "PID:$APP_PID file is empty and has been ignored."
    fi
else
    PID=`ps -ef|grep $APP_NAME| grep $APP_PORT |grep "opt"| awk '{printf \$2}'`
    kill -0  $PID >/dev/null 2>&1
        if [ $? -gt 0 ]; then
            echo "$APP_PID file does not exist. Is running?"
            exit 0
        else
            echo "$PID" > "$APP_PID"
        fi
fi
}

start() {
  checkStart
  
  echo "Starting $APP_NAME:$APP_PORT"

  ## 设置全局变量
  CUR_PATH=$(cd "$(dirname "$0")"; pwd)
  if [ -f "$CUR_PATH"/setenv.sh ]; then
    if [ -r "$CUR_PATH"/setenv.sh ]; then
      . "$CUR_PATH"/setenv.sh
    fi
  fi

  ## 设置应用变量
  if [ -f "$APP_HOME"/setenv-"$APP_PORT".sh ]; then
    if [ -r "$APP_HOME"/setenv-"$APP_PORT".sh ]; then
        echo "导入实例环境变量文件"
        . "$APP_HOME"/setenv-"$APP_PORT".sh
    fi
  elif [ -f "$APP_HOME"/setenv.sh ]; then
    if [ -r "$APP_HOME"/setenv.sh ]; then
        echo "导入公用环境变量文件"
        . "$APP_HOME"/setenv.sh
    fi
  fi

  JMX_OPTS="-Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.port=1$APP_PORT -Dcom.sun.management.jmxremote.ssl=false"

  ## 设置变量
  [ -z "$APP_OPTS" ] && APP_OPTS=
  APP_OPTS="$APP_OPTS -Dspring.profiles.active=$SPRING_PROFILES_ACTIVE -Dtomcat.port=$APP_PORT -Djava.io.tmpdir=$TMP_PATH $PINPOINT $JMX_OPTS"
  if [  ! -f $JAVA ];then
        echo wrong java path!modify /home/finance/appshell/setenv.sh!
        exit 1
  fi
  ## 服务启动
  if [ $CURRENT_USER == "root" ]; then
    #su $APP_USER -c "nohup $JAVA -jar $APP_OPTS $APP_JAR >/dev/null 2>&1 & echo \$! > $APP_PID"
    su $APP_USER -c "nohup $JAVA -jar $APP_OPTS $APP_JAR >log.log 2>&1 & echo \$! > $APP_PID"
  else
    `nohup $JAVA -jar $APP_OPTS $APP_JAR >/dev/null 2>&1 & echo \$! > $APP_PID`
  fi
  
  echo "Application $APP_NAME:$APP_PORT started."
}

stop() {
  echo "Stopping $APP_NAME:$APP_PORT"

  checkPid

  ## 服务停止 
  http_code=`curl -X POST -I -m 10 -o /dev/null -s -w %{http_code} $APP_SHUTDOWN_URI`

  if [[ $http_code != "200" ]]; then
    echo "The stop command failed. Attempting to signal the process to stop through OS signal."
    kill -15 `cat "$APP_PID"` >/dev/null 2>&1
  fi

  SLEEP=10
  if [ -f "$APP_PID" ]; then
    while [ $SLEEP -ge 0 ];do
      kill -0 `cat "$APP_PID"` >/dev/null 2>&1
      if [ $? -gt 0 ]; then
        rm -f "$APP_PID" >/dev/null 2>&1
        if [ $? != 0 ]; then
          if [ -w "$APP_PID" ]; then
            cat /dev/null > "$APP_PID"
          else
            echo "The PID file could not be removed or cleared."
          fi
        fi
        echo "Application $APP_NAME:$APP_PORT stopped."
        break
      fi
      if [ $SLEEP -gt 0 ]; then
        sleep 1
      fi
      SLEEP=`expr $SLEEP - 1 `
    done
  fi

  KILL_SLEEP=5
  if [  -f "$APP_PID" ]; then
    if [ -s "$APP_PID" ]; then
      PID=`cat "$APP_PID"`
      echo "Killing application $APP_NAME:$APP_PORT with the PID: $PID"
      kill -9 $PID
      while [ $KILL_SLEEP -ge 0 ]; do
        kill -0 `cat "$APP_PID"` >/dev/null 2>&1
        if [ $? -gt 0 ]; then
            rm -f "$APP_PID" >/dev/null 2>&1
            if [ $? != 0 ]; then
                if [ -w "$APP_PID" ]; then
                    cat /dev/null > "$APP_PID"
                else
                    echo "The PID file could not be removed."
                fi
            fi
            # Set this to zero else a warning will be issued about the process still running
            KILL_SLEEP=0
            echo "The application $APP_NAME:$APP_PORT process has been killed."
            break
        fi
        if [ $KILL_SLEEP -gt 0 ]; then
            sleep 1
        fi
        KILL_SLEEP=`expr $KILL_SLEEP - 1 `
      done

      if [ $KILL_SLEEP -gt 0 ]; then
          echo "Application $APP_NAME:$APP_PORT has not been killed completely yet. The process might be waiting on some system call or might be UNINTERRUPTIBLE."
      fi
    fi
  fi
}

stack() {
  checkPid
  PID=`cat "$APP_PID"`
  jstack_file=$APP_LOGS/jstack-$APP_PORT-$PID-$TIME_NOW.dump

  echo "Dump thread stack $APP_NAME:$APP_PORT, pid:$PID, file: $jstack_file"
  
  if [ $CURRENT_USER == "root" ]; then
    su $APP_USER -c "jstack -F -l $PID > $jstack_file 2>&1"
  else
    jstack -F -l $PID > $jstack_file 2>&1
  fi
  
}

heap() {
  checkPid
  PID=`cat "$APP_PID"`
  heap_file=heap-$APP_PORT-$PID-$TIME_NOW.dump

  echo "Dump jvm head $APP_NAME:$APP_PORT, pid:$PID, file: $heap_file"
  
  if [ $CURRENT_USER == "root" ]; then
    su $APP_USER -c "jmap -F -dump:format=b,file=$heap_file $PID 2>&1"
  else
    jmap -F -dump:format=b,file=$heap_file $PID 2>&1
  fi
 
}

status() {
  servers=0
  for server_port in `ls -a $APP_SERVERS`
  do  
    if [ x"$server_port" != x"." -a x"$server_port" != x".." ]; then
      if [ -d "$APP_SERVERS"/"$server_port" ]; then
        servers=$((servers+1))
        server_status="stopped"
        server_pid="$APP_SERVERS"/"$server_port"/pid
        if [ -f "$server_pid" ]; then
          if [ -s "$server_pid" ]; then
            kill -0 `cat "$server_pid"` >/dev/null 2>&1
            if [ $? -eq 0 ]; then
              server_status="running"
            fi
          fi
        fi
        echo "$servers. $server_port:$server_status"
      fi
    fi
  done
}

case "$1" in
  start)
    start
    ;;
  stop)
    stop
    ;;
  restart)
    stop
    echo "Sleep 10 seconds for eureka check"
    sleep 10
    start
    ;;
  status)
    status
    ;;
  stack)
    stack
    ;;  
  heap)
    heap
    ;;
  *)
    echo "Usage: $0 {start|stop|restart|status|stack|heap} app_name [app_port]"
    RETVAL=1
esac

exit $RETVAL
